home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / m2 / cat3src / cat / editbase.i < prev    next >
Text File  |  1997-10-26  |  58KB  |  1,803 lines

  1. IMPLEMENTATION MODULE EditBase;
  2.  
  3. FROM SYSTEM    IMPORT ADDRESS, ADR, TSIZE, CALLSYS, CADR, CODE;
  4. FROM Storage   IMPORT ALLOCATE, DEALLOCATE;
  5. IMPORT Block;
  6.  
  7. IMPORT BinOps;
  8. IMPORT Storage;
  9.  
  10. IMPORT AssFuncs;
  11. IMPORT EditTypes;
  12. FROM EditTypes IMPORT EDITPTR;
  13.  
  14. FROM Void    IMPORT v;
  15.  
  16. CONST   Debug = FALSE;
  17.  
  18. CONST   CR      = 15C;
  19.         LF      = 12C;
  20.  
  21. TYPE copyFunction = PROCEDURE (ADDRESS, ADDRESS, LONGCARD);
  22.  
  23. VAR CopyBlock : copyFunction;
  24.  
  25. PROCEDURE blockCopy (from, to : ADDRESS; len : LONGCARD);
  26. BEGIN
  27.   Block.Copy (from, len, to);
  28. END blockCopy;
  29.  
  30. (*$? Debug:
  31. (* Debug - Funktionen, fliegen in der endgltigen Version raus *)
  32.  
  33. PROCEDURE checkBuffer (VAR buff : EditTypes.aBufferPtr);
  34.   VAR used : LONGINT; 
  35.       i    : INTEGER;
  36. BEGIN
  37.   used := 0;
  38.   WITH buff^ DO
  39.     FOR i := 0 TO SHORT(toLine - fromLine) DO
  40.       IF lines # NIL THEN INC (used, lines^[i]); END;
  41.     END;
  42.       CALLSYS (1, 4201, CADR("used gez„hlt: %ld, eingetragen: %d"), used, usedMem);
  43.       CALLSYS (1, 4201, CADR("MaxLines: %d"), maxLine);
  44.       CALLSYS (1, 4201, CADR("fromLine: %ld"), fromLine);
  45.       CALLSYS (1, 4201, CADR("toLine: %ld"), toLine);
  46.       CALLSYS (1, 4201, CADR("usedLines: %ld"), toLine - fromLine + 1);
  47.     IF used # LONG(usedMem) THEN
  48.       HALT
  49.     END; 
  50.   END;
  51. END checkBuffer;
  52.  
  53. PROCEDURE TestStructure (ed : EDITPTR);
  54.   VAR buf : EditTypes.aBufferPtr;
  55.       bufNum : INTEGER;
  56.       used   : INTEGER;
  57.       i      : INTEGER;
  58. BEGIN
  59.   WITH ed^ DO
  60.     CALLSYS (1, 4201, CADR("Teste Struktur und Fllungsgrad ..."));
  61.     buf := firstBuff;
  62.     bufNum := 1;
  63.     WHILE buf # NIL DO
  64.       WITH buf^ DO
  65.         used := 0;
  66.         FOR i := 0 TO SHORT(toLine - fromLine) DO
  67.           INC (used, lines^[i]);
  68.         END;
  69.         CALLSYS (1, 4201, CADR("Buffer Nummer: %d"), bufNum);
  70.         CALLSYS (1, 4201, CADR("usedMem: %d"), usedMem);
  71.         CALLSYS (1, 4201, CADR("used by count: %d"), used);
  72.         CALLSYS (1, 4201, CADR("MaxLines: %d"), maxLine);
  73.         CALLSYS (1, 4201, CADR("fromLine: %ld"), fromLine);
  74.         CALLSYS (1, 4201, CADR("toLine: %ld"), toLine);
  75.         CALLSYS (1, 4201, CADR("usedLines: %ld"), toLine - fromLine + 1);
  76.       END;
  77.       buf := buf^.next;
  78.       INC (bufNum);
  79.     END;
  80.     CALLSYS (1, 4201, CADR("totalLineNr: %ld"), totalLineNr);
  81.   END;
  82. END TestStructure;
  83. *)
  84.  
  85.  
  86. PROCEDURE findLineNum (VAR ed : EDITPTR; lineNum : LONGINT): BOOLEAN;
  87. BEGIN
  88.   WITH ed^ DO
  89.     (* Erst mal Buffer suchen und CurrentBuff entsprechend setzen *)
  90.     IF firstBuff = NIL THEN RETURN FALSE END;
  91.     IF currentBuff = NIL THEN currentBuff := firstBuff END;
  92.     IF (lineNum > currentBuff^.toLine)
  93.     THEN 
  94.       WHILE (currentBuff # NIL) & (lineNum > currentBuff^.toLine) DO
  95.         currentBuff := currentBuff^.next;
  96.       END;
  97.     ELSIF (lineNum < currentBuff^.fromLine) 
  98.     THEN
  99.       (* Nach vorne suchen (rckw„rts) *)
  100.       WHILE (currentBuff # NIL) & (lineNum < currentBuff^.fromLine) DO
  101.         currentBuff := currentBuff^.prev;
  102.       END;
  103.     END;
  104.     IF currentBuff = NIL
  105.     THEN
  106.       (*$? Debug:
  107.       IF lineNum # totalLineNr
  108.       THEN
  109.         CALLSYS (1, 4201, CADR("Fehler bei Anforderung von Zeilenadresse"));
  110.         CALLSYS (1, 4201, CADR("Angeforderte Zeile: %ld, maxZeile: %ld"), lineNum, totalLineNr);
  111.         HALT;
  112.       END;
  113.       *)
  114.       currentBuff := firstBuff;
  115.       RETURN FALSE
  116.     ELSE
  117.       RETURN TRUE;
  118.     END;
  119.   END;
  120. END findLineNum;
  121.  
  122. PROCEDURE createBuffer (defSize : INTEGER) : EditTypes.aBufferPtr;
  123.   VAR newBuff : EditTypes.aBufferPtr;
  124. BEGIN
  125.   (* Neuen Verwaltungsblock anlegen *)
  126.   IF defSize = 0 THEN defSize := memBlockSize; END;
  127.   NEW (newBuff);
  128.   (* Wenn wir jetzt nicht genug Speicher haben, dann ist eh alles vorbei *)
  129.   IF newBuff = NIL THEN RETURN NIL END;
  130.   (* Textspeicher allozieren *)
  131.   ALLOCATE (newBuff^.buffer, defSize);
  132.   IF newBuff^.buffer = NIL THEN DISPOSE (newBuff); RETURN NIL END;
  133.   Block.Clear (newBuff^.buffer, defSize);
  134.   newBuff^.bufSize := defSize;
  135.   newBuff^.fromLine := 0;
  136.   newBuff^.toLine := 0;
  137.   newBuff^.usedMem := 0;
  138.   newBuff^.maxLine := 0;
  139.   newBuff^.lines := NIL;
  140.   RETURN newBuff;
  141. END createBuffer;
  142.  
  143. PROCEDURE copyBuffer (VAR ed : EDITPTR; line : LONGINT; VAR newBuff : EditTypes.aBufferPtr; 
  144.                       VAR copyLines : INTEGER; copyOnly : BOOLEAN) : BOOLEAN;
  145. (* Kopiert aus dem aktuellen Buffer ab Zeile line in neuen Buffer newBuff.
  146.  * Wenn line < 0 ist, dann wird nach Prozenten gesplittet. 
  147.  *)
  148.  VAR i       : INTEGER;
  149.      offSet2 : INTEGER;
  150.      usedLines : INTEGER;
  151. BEGIN
  152.   WITH ed^.currentBuff^ DO
  153.     newBuff := createBuffer(0);
  154.     IF newBuff = NIL THEN RETURN FALSE END;
  155.     (* Nun Kopierposition feststellen *)
  156.     offSet2 := 0;
  157.     usedLines := SHORT (toLine - fromLine);
  158.     IF ~(copyOnly OR (line >= 0))
  159.     THEN
  160.       (* Jetzt Bytes und Zeilen zum Splitten feststellen *)
  161.       i := 0;
  162.       WHILE (offSet2 < usedMem DIV 2) & (i <= usedLines) DO
  163.         INC (offSet2, lines^[i]);
  164.         INC (i);
  165.       END;
  166.     ELSE
  167.       IF line > toLine THEN
  168.         eReason := notFound;
  169.         RETURN FALSE
  170.       END;
  171.       FOR i := 0 TO SHORT(line-fromLine) DO 
  172.         INC (offSet2, lines^[i]);
  173.       END;
  174.       i := SHORT(line - fromLine)+1;
  175.     END;
  176.     copyLines := i;
  177.     (* In i steht die relative Zeilennummer im Buffer, ab der in den 
  178.      * neuen Buffer kopiert wird.
  179.      *)
  180.     newBuff^.maxLine := BinOps.HigherInt(200, SHORT(toLine-fromLine-LONG(i))*2);
  181.     ALLOCATE (newBuff^.lines, LONG(newBuff^.maxLine) * TSIZE (INTEGER));
  182.     IF newBuff^.lines = NIL 
  183.     THEN 
  184.       DEALLOCATE (newBuff^.buffer, 0);
  185.       DISPOSE (newBuff);
  186.       RETURN FALSE 
  187.     END;
  188.     (* So, jetzt k”nnen wir auch kopieren *)
  189.     (* Text kopieren *)
  190.     CopyBlock (ADR (buffer^[offSet2]), newBuff^.buffer, usedMem - offSet2);
  191.     newBuff^.usedMem := usedMem - offSet2;
  192.     IF ~copyOnly THEN usedMem := offSet2; END;
  193.     (* Zeilenarray kopieren *)
  194.     CopyBlock (ADR(lines^[i]), newBuff^.lines, (toLine - fromLine - LONG(i)+1) * TSIZE (INTEGER));
  195.     (* Zeilennummern in neuen Buffer schreiben *)
  196.     newBuff^.fromLine := fromLine + LONG(i);
  197.     newBuff^.toLine   := toLine;
  198.   END;
  199.   RETURN TRUE;
  200. END copyBuffer;
  201.  
  202. PROCEDURE splitBuffer (VAR ed : EDITPTR; line: LONGINT) : BOOLEAN;
  203. (* Splittet den aktuellen Buffer auf und h„ngt einen neuen 
  204.  * Buffer hinter den aktuellen. 
  205.  * Falls line >= 0 ist, wird hinter line gesplittet. Line ist die 
  206.  * Zeilennummer in diesem Buffer!
  207.  * FALSE: Nicht genug Speicher, eReason wird gesetzt
  208.  *)
  209.  VAR newBuff : EditTypes.aBufferPtr;
  210.      i       : INTEGER;
  211. BEGIN
  212.   WITH ed^.currentBuff^ DO
  213.     IF ~copyBuffer (ed, line, newBuff, i, FALSE)
  214.     THEN 
  215.       RETURN FALSE
  216.     END;
  217.     (* Jetzt haben wir alles alloziert, jetzt k”nnen wir den neuen 
  218.      * Buffer in die Liste einh„ngen 
  219.      *)
  220.     newBuff^.prev := ed^.currentBuff;
  221.     newBuff^.next := next;
  222.     IF newBuff^.next # NIL
  223.     THEN
  224.       newBuff^.next^.prev := newBuff;
  225.     END;
  226.     ed^.currentBuff^.next := newBuff;
  227.     newBuff^.fromLine := fromLine + LONG(i);
  228.     newBuff^.toLine := toLine;
  229.     toLine := fromLine + LONG(i-1);
  230.     (* Jetzt noch die Buffer berprfen *)
  231.   END (* WITH ed^.currentBuff^ *);
  232.   RETURN TRUE;
  233. END splitBuffer;
  234.  
  235. PROCEDURE compactTwo (first, second : EditTypes.aBufferPtr; VAR freedSecond : BOOLEAN) : BOOLEAN;
  236. (* Bringt Daten aus dem zweiten Buffer in den ersten, so daž dieser zu
  237.  * ca. fillPercent gefllt wird
  238.  *)
  239.  CONST fillPercent = 95L;
  240.  VAR   usedInSecond : INTEGER;
  241.        freeInFirst,
  242.        secIdx,
  243.        i            : INTEGER;
  244.        newLines     : INTEGER;
  245.        newArray     : EditTypes.lineArrayPtr;
  246. BEGIN
  247.   freedSecond := FALSE;
  248.   IF (LONG(first^.usedMem) * 100L) DIV LONG(first^.bufSize) < fillPercent
  249.   THEN
  250.     freeInFirst := SHORT((LONG(first^.bufSize) * fillPercent) DIV 100L) - first^.usedMem;
  251.     (* Jetzt in zweitem Buffer suchen, bis freeInFirst Bytes berschritten *)
  252.     usedInSecond := 0;
  253.     secIdx := 0;
  254.     WITH second^ DO
  255.       WHILE (secIdx <= SHORT(toLine - fromLine)) & (usedInSecond + lines^[secIdx] < freeInFirst) DO
  256.         INC (usedInSecond, lines^[secIdx]);
  257.         INC (secIdx);
  258.       END;
  259.     END;
  260.     (* Jetzt haben wir die Anzahl Bytes, die zu verschieben sind *)
  261.     IF (usedInSecond = 0) OR (freeInFirst = 0) THEN RETURN TRUE END;
  262.     (* Jetzt nachsehen, ob das LineArray in first grož genug ist *)
  263.     WITH first^ DO
  264.       newLines := SHORT(toLine-fromLine) + secIdx;
  265.       IF newLines >= maxLine 
  266.       THEN
  267.         (* lineArray zu klein, neu allozieren! *)
  268.         IF newLines < $4000 
  269.         THEN
  270.           newLines := BinOps.HigherInt (200, newLines * 2);
  271.         ELSIF newLines < bufSize-100
  272.         THEN
  273.           INC (newLines,100);
  274.         ELSE
  275.           (* Zu viele Zeilen in einem Block! *)
  276.           HALT
  277.         END;
  278.         ALLOCATE (newArray, LONG(newLines) * TSIZE (INTEGER));
  279.         IF newArray = NIL THEN RETURN FALSE END;
  280.         (* Ok, wir haben ein neues lineArray *)
  281.         FOR i := 0 TO SHORT (toLine - fromLine) DO
  282.           newArray^[i] := lines^[i]
  283.         END;
  284.         maxLine := newLines;
  285.         DEALLOCATE (lines, 0);
  286.         lines := newArray;
  287.       END;
  288.       (* Jetzt lineArray aus zweitem Buffer kopieren *)
  289.       FOR i := 0 TO secIdx-1 DO
  290.         lines^[SHORT (toLine-fromLine) + i + 1] := second^.lines^[i];
  291.       END;
  292.       (* Jetzt Speicherbereich umkopieren *)
  293.       CopyBlock (second^.buffer,ADR(first^.buffer^[usedMem]), usedInSecond);
  294.     END;
  295.     WITH second^ DO
  296.       (* Jetzt lineArray in zweitem Buffer umkopieren *)
  297.       FOR i := secIdx TO SHORT(toLine-fromLine) DO
  298.         lines^[i - secIdx] := lines^[i];
  299.       END;
  300.       (* Jetzt Speicher intern umkopieren *)
  301.       CopyBlock (ADR(buffer^[usedInSecond]),buffer, usedMem - usedInSecond);
  302.     END; 
  303.     (* Jetzt noch die usedMems und die Zeilen anpassen *)
  304.     INC (first^.usedMem, usedInSecond);
  305.     DEC (second^.usedMem, usedInSecond);
  306.     INC (first^.toLine, secIdx);
  307.     INC (second^.fromLine, secIdx);
  308.     (* Jetzt noch testen, ob evtl. der zweite Buffer leer geworden ist: *)
  309.     IF second^.usedMem = 0
  310.     THEN
  311.       (* Buffer komplett freigeben und aus Liste aush„ngen *)
  312.       first^.next := second^.next;
  313.       IF second^.next # NIL THEN
  314.         second^.next^.prev := second^.prev;
  315.       END;
  316.       DEALLOCATE (second^.buffer, 0);
  317.       DEALLOCATE (second^.lines, 0);
  318.       DISPOSE (second);
  319.       freedSecond := TRUE
  320.     END;
  321.   END;
  322.   RETURN TRUE;
  323. END compactTwo;
  324.  
  325. PROCEDURE deleteLineBlock (VAR ed : EDITPTR; lineFrom, lineTo : LONGINT) : BOOLEAN;
  326.   VAR i, lineIdx, lineCount,
  327.       len, offset : INTEGER;
  328. BEGIN
  329.   WITH ed^.currentBuff^ DO 
  330.     IF (lineFrom < fromLine) OR (lineTo < fromLine) OR (lineTo > toLine) OR (lineFrom > toLine)
  331.     THEN 
  332.       RETURN FALSE
  333.     END;
  334.     offset := 0;
  335.     FOR i := 0 TO SHORT(lineFrom - fromLine) - 1 DO
  336.       INC (offset, lines^[i]);
  337.     END;
  338.     lineCount := SHORT(lineTo - lineFrom) + 1;
  339.     lineIdx := SHORT(lineFrom - fromLine);
  340.     len := 0;
  341.     FOR i := SHORT(lineFrom - fromLine) TO SHORT(lineFrom - fromLine) + lineCount  - 1 DO
  342.       INC( len, lines^[i]);
  343.     END;
  344.     (* LineArray anpassen *)
  345.     CopyBlock (ADR(lines^[lineIdx+lineCount]), ADR(lines^[lineIdx]), (SHORT (toLine - lineTo) + 1) * TSIZE (INTEGER)); 
  346.     (* Im Speicher verschieben *)
  347.     CopyBlock (ADR (buffer^[offset+len]), ADR (buffer^[offset]), usedMem - offset - len);
  348.     (* usedMem anpassen *)
  349.     DEC (usedMem, len);
  350.   END; (* WITH *)
  351.   RETURN TRUE;
  352. END deleteLineBlock;
  353.  
  354. PROCEDURE countLines (buff: EditTypes.aBufferPtr) : INTEGER;
  355. (* Z„hlt die Zeilen in einem Buffer *)
  356.   VAR lineCount : INTEGER;
  357.       idx2      : INTEGER;
  358.       ch        : CHAR;
  359. BEGIN
  360.   WITH buff^ DO
  361.     (* Zeilen z„hlen *)
  362.     lineCount := 0;
  363.     idx2 := 0;
  364.     WHILE idx2 < usedMem DO
  365.       idx2 := SHORT(AssFuncs.findLineEnd (buffer, idx2, usedMem));
  366.       ch := buffer^[idx2];
  367.       IF (ch = LF) OR (ch = CR) OR (ch = 0C) OR (idx2 > usedMem)
  368.       THEN
  369.         INC (lineCount);
  370.         INC(idx2);
  371.         IF ((buffer^[idx2] = LF) OR (buffer^[idx2] = CR)) & (buffer^[idx2] # ch)  THEN INC (idx2) END;
  372.       END;
  373.     END;
  374.   END (* WITH buff^ DO *);
  375.   RETURN lineCount;
  376. END countLines;
  377.  
  378. PROCEDURE fillLineArray(buff: EditTypes.aBufferPtr);
  379. (* Fllt das Zeilenarray zu einem Buffer *)
  380.   VAR lineCount : INTEGER;
  381.       idx2      : INTEGER;
  382.       lastIdx   : INTEGER;
  383.       lineLen   : INTEGER;
  384.       ch        : CHAR;
  385. BEGIN
  386.   WITH buff^ DO
  387.     (* Jetzt nur noch das ZeilenArray fllen *)
  388.     lineCount := 0;
  389.     idx2 := 0;
  390.     lastIdx := 0;
  391.     lineLen := 0;
  392.     WHILE idx2 < usedMem DO
  393.       idx2 := SHORT(AssFuncs.findLineEnd (buffer, idx2, usedMem));
  394.       (*
  395.       WHILE (idx2 < usedMem) & (ch # CR) & (ch # LF) DO
  396.         INC (idx2); INC (lineLen); ch := text^[idx2];
  397.       END;
  398.       *)
  399.       ch := buffer^[idx2];
  400.       IF (ch = LF) OR (ch = CR) OR (ch = 0C) OR (idx2 > usedMem)
  401.       THEN
  402.         INC (idx2);
  403.         IF idx2 > usedMem THEN idx2 := usedMem END;
  404.         lineLen := idx2 - lastIdx;
  405.         IF ((buffer^[idx2] = LF) OR (buffer^[idx2] = CR)) & (buffer^[idx2] # ch)  THEN INC (idx2); INC (lineLen); END;
  406.         lines^[lineCount] := lineLen;
  407.         INC (lineCount);
  408.         (* Notbremse *)
  409.         IF lineCount >= maxLine THEN RETURN END;
  410.         lineLen := 0;
  411.         lastIdx := idx2;
  412.       END;
  413.     END;
  414.   END (* WITH buff^ DO *)
  415. END fillLineArray;
  416.  
  417. PROCEDURE FixLine (ed : EDITPTR; line: LONGINT);
  418.   VAR len, l : INTEGER;
  419.       txt    : EditTypes.textPtr;
  420. BEGIN
  421.   WITH ed^ DO
  422.     v.bool := GetLineLength (ed, line, len);
  423.     ALLOCATE (txt, len+4);
  424.     IF txt = NIL
  425.     THEN
  426.       RETURN
  427.     END;
  428.     v.bool := GetLine (ed, line, txt^, len);
  429.     (* Jetzt Zeile testen *)
  430.     l := LENGTH (txt^);
  431.     IF (txt^[l] # CR) & (txt^[l] # LF)
  432.     THEN
  433.       (* CR/LF anh„ngen *)
  434.       txt^[l] := CR;
  435.       txt^[l+1] := LF;
  436.       txt^[l+2] := 0C;
  437.       l := LENGTH (txt^);
  438.       v.bool := PutLine (ed, line, txt^, l);
  439.     END;
  440.     (* Speicher wieder freigeben *)
  441.     DEALLOCATE (txt, 0);
  442.   END;
  443. END FixLine;
  444.  
  445. PROCEDURE FixBuffer (ed: EDITPTR);
  446.   VAR oldLines,
  447.       lineCount : INTEGER;
  448.       
  449.       addLines,
  450.       oldTo     : LONGINT;
  451.       tBuf      : EditTypes.aBufferPtr;
  452.       doHalt    : BOOLEAN;  (* Halt am Ende? *)
  453. BEGIN
  454.   doHalt := FALSE;
  455.   WITH ed^ DO
  456.     WITH currentBuff^ DO
  457.       (* Erstmal letzte Zeile im Buffer holen und testen 
  458.       FixLine (ed, toLine);
  459.       *)
  460.       (* So, und jetzt die Struktur des Buffers nochmal neu aufbauen *)
  461.       lineCount := countLines (currentBuff);
  462.       (* Wir haben also jetzt lineCount Zeilen in dem Buffer.
  463.        * Jetzt nachsehen, ob wir das Zeilenarray neu allozieren mssen 
  464.        *)
  465.       IF lineCount >= maxLine
  466.       THEN
  467.         oldLines := maxLine;
  468.         maxLine := BinOps.HigherInt (100, (lineCount * 3) DIV 2);
  469.         DEALLOCATE (lines, 0);
  470.         ALLOCATE (lines, LONG(maxLine) * TSIZE (INTEGER));
  471.         IF lines = NIL 
  472.         THEN 
  473.           (* Shit! Kein Speicher mehr! *)
  474.           maxLine := lineCount + 1;
  475.           ALLOCATE (lines, LONG(maxLine) * TSIZE (INTEGER));
  476.           IF lines = NIL
  477.           THEN
  478.             (* Wir haben ein echtes Problem: Das alte Zeilenarray ist futsch, 
  479.              * und fr das neue ist nicht genug Platz da!
  480.              * Da kann ich nur hoffen, daž das nie auftritt!
  481.              * Erstmal alten Speicher wieder allozieren und dann
  482.              * das Zeilenarray soweit fllen, wie es geht, und dann 
  483.              * die Notbremse treten.
  484.              *)
  485.             ALLOCATE (lines, LONG(oldLines) * TSIZE (INTEGER));
  486.             IF lines = NIL
  487.             THEN
  488.               (* Auch fr das alte Array kein Speicher mehr?
  489.                * Dann ist jetzt alles vorbei, es hat auch  keinen
  490.                * Zweck mehr, irgendwelche Rettungsversuche zu 
  491.                * unternehmen.
  492.                *)
  493.               HALT;
  494.             ELSE
  495.               doHalt := TRUE;
  496.             END;
  497.           END;
  498.         END;
  499.       END;
  500.       oldTo := toLine;
  501.       toLine := fromLine + LONG(lineCount) - 1;
  502.       (* neue toLine berechnen *)
  503.       addLines := toLine - oldTo;
  504.       
  505.       fillLineArray (currentBuff);
  506.  
  507.     END (* WITH currentBuff^ *);
  508.     (* Jetzt noch Zeilennummern in folgenden Buffern 
  509.      * korrigieren.
  510.      *)
  511.     tBuf := currentBuff^.next;
  512.     WHILE tBuf # NIL DO
  513.       INC (tBuf^.fromLine, addLines);
  514.       INC (tBuf^.toLine, addLines);
  515.       tBuf := tBuf^.next;
  516.     END;
  517.     INC (totalLineNr, addLines);
  518.  
  519.     (* Jetzt die Notbremse ziehen *)
  520.     IF doHalt THEN HALT END;
  521.   END (* WITH ed^ DO *)
  522. END FixBuffer;
  523.  
  524. (* Exportierte Prozeduren *)
  525.  
  526. PROCEDURE InsertBuffer (VAR ed : EDITPTR; VAR buff : ADDRESS; len : LONGCARD; freeBuffer: BOOLEAN): BOOLEAN;
  527.   (* Es wird ein Text aus einem Buffer in ed an der aktuellen Stelle eingefgt.
  528.    * Vorgehensweise:
  529.    * Die Einfgeposition wird gemerkt, ebenso der Zeilenindex davon. Dann wird 
  530.    * die Einfgeposition im Buffer berechnet und nachgesehen, wieviel Platz
  531.    * noch im Buffer ist. Wenn noch gengend Platz in dem Buffer ist, wird
  532.    * der Teil hinter der Einfgeposition um len Bytes nach hinten verschoben
  533.    * und danach das Zeilenarray einfach komplett neu aufgebaut. 
  534.    * Sollte nicht gengend Platz vorhanden sein, dann wird hinter der Einfgestelle
  535.    * der Buffer gesplittet und solange neue Buffer angelegt, bis der Text komplett hinein-
  536.    * pažt. Danach wird dann der buffer einkopiert und das Zeilenarray ab dem ersten Buffer,
  537.    * in den eingefgt wurde, neu aufgebaut. 
  538.    * Es wird auch noch festgestellt, wieviele Zeilen eingefgt wurden, so daž bei Bl”cken
  539.    * die Endposition bestimmt werden kann.
  540.    * Umbruch wird keiner vorgenommen.
  541.    *)
  542.   PROCEDURE appendToBuffer (buf : ADDRESS; len : LONGCARD; offset: INTEGER; startByte, freeBytes : LONGCARD): BOOLEAN;
  543.     VAR ptr     : POINTER TO ARRAY [0..$FFFFFFFF] OF CHAR;
  544.         idx     : LONGCARD;
  545.         i       : LONGCARD;
  546.         first   : BOOLEAN;
  547.         ch      : CHAR;
  548.   BEGIN 
  549.     (* Jetzt ersten Teil aus Buffer einkopieren *)
  550.     first := TRUE;
  551.     ptr := buf;
  552.     idx := 0;   (* Index in Buffer *)
  553.     REPEAT
  554.       IF ~first
  555.       THEN
  556.         IF ~GetBuffer (ed, 0) THEN
  557.           RETURN FALSE
  558.         END;
  559.         startByte := (LONGCARD(LONG(ed^.currentBuff^.bufSize)) * 19) DIV 20; (* Wir wollen den Buffer zu 95% fllen *)
  560.         freeBytes := LONGCARD(LONG(ed^.currentBuff^.bufSize));
  561.       END;
  562.       IF idx + startByte < len
  563.       THEN
  564.         (* Von Index idx+26000 vorw„rts nach letztem Zeilenende suchen *)
  565.         i := AssFuncs.findLineEnd (buf, idx+startByte, idx + freeBytes);
  566.         ch := ptr^[i];
  567.         (*
  568.         i := idx + 26000L;
  569.         ch := ptr^[i];
  570.         WHILE (ch # CR) & (ch # LF) & (i < idx + $8000) DO
  571.           INC (i); ch := ptr^[i];
  572.         END;
  573.         *)
  574.         IF i >= idx + freeBytes - 2 (* -2 fr CR/LF! *)
  575.         THEN
  576.           (* Shit, keines mehr gefunden *)
  577.           i := idx + startByte;
  578.           ch := ptr^[i];
  579.           WHILE (ch # CR) & (ch # LF) & (i > idx) DO
  580.             DEC (i); ch := ptr^[i];
  581.           END;
  582.           IF i = idx THEN RETURN FALSE END;
  583.         ELSE
  584.           IF ((ptr^[i+1] = CR) OR (ptr^[i+1] = LF)) & (ptr^[i+1] # ch) THEN INC (i) END;
  585.         END;
  586.         INC(i);
  587.       ELSE
  588.         i := len;
  589.       END;
  590.       IF first
  591.       THEN
  592.         CopyBlock (ADR(ptr^[idx]), ADR(ed^.currentBuff^.buffer^[offset]), i - idx);
  593.         INC (ed^.currentBuff^.usedMem, INTEGER(SHORT(i-idx)));
  594.       ELSE
  595.         CopyBlock (ADR(ptr^[idx]), ed^.currentBuff^.buffer, i - idx);
  596.         ed^.currentBuff^.usedMem := INTEGER(SHORT(i - idx)); 
  597.       END;
  598.       idx := i;
  599.       first := FALSE;
  600.     UNTIL idx >= len;
  601.     RETURN TRUE;
  602.   END appendToBuffer;    
  603.   
  604.   VAR 
  605.       lineCount : INTEGER;
  606.       
  607.       addLines,
  608.       oldTo,
  609.       insertLine: LONGINT;
  610.       insPos,
  611.       freeInBuff,
  612.       insertRow : INTEGER;
  613.       bBuf,
  614.       cBuf,
  615.       cNext,
  616.       tBuf      : EditTypes.aBufferPtr;
  617.       bUsed,
  618.       startByte : INTEGER;
  619.       tmpBuf    : ADDRESS;
  620.       tLen      : INTEGER;
  621.       first     : BOOLEAN;
  622.       startCount: LONGINT;
  623.       
  624. BEGIN
  625.   tmpBuf := NIL;
  626.   WITH ed^ DO
  627.     cBuf := currentBuff;
  628.     (* Einfgeposition merken *)
  629.     insertLine := currLineNr;
  630.     insertRow  := currRow;
  631.     (* Jetzt Offset in Buffer bestimmen und currentBuff setzen *)
  632.     insPos := GetOffset (ed);
  633.     IF insPos < 0 THEN 
  634.       (* Zeile nicht gefunden, am Ende anfgen *)
  635.       currentBuff := firstBuff;
  636.       WHILE currentBuff^.next # NIL DO 
  637.         currentBuff := currentBuff^.next;
  638.       END;
  639.       insPos := currentBuff^.usedMem;
  640.     END;
  641.     (* Jetzt nachsehen, wieviel Platz in currentBuff noch drin ist *)
  642.     freeInBuff := currentBuff^.bufSize - currentBuff^.usedMem;
  643.     IF len < VAL(LONGCARD,freeInBuff)
  644.     THEN
  645.       (* Gesamter Buffer pažt noch in aktuellen Buffer, nur ein
  646.        * paar Zeilen verschieben
  647.        *)
  648.       WITH currentBuff^ DO
  649.         (* Text hinter Einfgeposition verschieben *)
  650.         tLen := usedMem - insPos;
  651.         CopyBlock (ADR(buffer^[insPos]), ADR(buffer^[insPos+VAL(INTEGER,len)]), tLen);
  652.         (* Text aus buff einfgen *)
  653.         CopyBlock (buff, ADR(buffer^[insPos]), len);
  654.         (* Jetzt Speicher direkt freigeben *)
  655.  
  656.         IF freeBuffer THEN DEALLOCATE (buff, 0); buff := NIL; END;
  657.         
  658.         INC (usedMem, len);
  659.         (* Jetzt Zeilenarray neu berechnen.
  660.          * Erst mal Zeilen z„hlen in Buffer 
  661.          *)
  662.  
  663.         lineCount := countLines (currentBuff);
  664.         (* Wir haben also jetzt lineCount Zeilen in dem Buffer.
  665.          * Jetzt nachsehen, ob wir das Zeilenarray neu allozieren mssen 
  666.          *)
  667.         IF lineCount >= maxLine
  668.         THEN
  669.           maxLine := BinOps.HigherInt (100, SHORT(BinOps.LowerLInt (32000L, (LONG(lineCount) * 3))) DIV 2);
  670.           DEALLOCATE (lines, 0);
  671.           ALLOCATE (lines, LONG(maxLine) * TSIZE (INTEGER));
  672.           IF lines = NIL 
  673.           THEN 
  674.             (* Shit! Kein Speicher mehr! *)
  675.             (* Also wieder zurckkopieren und zurck *)
  676.             CopyBlock (ADR(buffer^[insPos+VAL(INTEGER,len)]), ADR(buffer^[insPos]), tLen);
  677.             DEC (usedMem, len);
  678.             RETURN FALSE
  679.           END;
  680.         END;
  681.         oldTo := toLine;
  682.         toLine := fromLine + LONG(lineCount) - 1;
  683.         (* neue toLine berechnen *)
  684.         addLines := toLine - oldTo;
  685.         
  686.         fillLineArray (currentBuff);
  687.  
  688.       END (* WITH currentBuff^ *);
  689.       (* Jetzt noch Blockende ggf. feststellen und Zeilennummern in folgenden Buffern 
  690.        * korrigieren.
  691.        *)
  692.       tBuf := currentBuff^.next;
  693.       WHILE tBuf # NIL DO
  694.         INC (tBuf^.fromLine, addLines);
  695.         INC (tBuf^.toLine, addLines);
  696.         tBuf := tBuf^.next;
  697.       END;
  698.       INC (totalLineNr, addLines);
  699.       
  700.       (* Jetzt Blockende holen *)
  701.       IF block THEN 
  702.         GetPos (ed, insPos+VAL(INTEGER,len), blocks[0].blockEnd.line, blocks[0].blockEnd.row); 
  703.       END;
  704.       currentBuff := firstBuff;
  705.       v.bool := findLineNum (ed, currLineNr);
  706.     ELSE
  707.       (* Buffer pažt nicht in currentBuff.
  708.        * Jetzt machen wir das folgendermažen: Wir kopieren alles hinter der Einfgepositon 
  709.        * aus dem aktuellen Buffer in einen tempor„ren Buffer, dann kopieren wir den ersten 
  710.        * Teil des Textes in den aktuellen Buffer. Danach h„ngen wir weitere Buffer an, bis der
  711.        * Text komplett drin ist und h„ngen dann noch den tempor„ren Buffer an.
  712.        *)
  713.       WITH currentBuff^ DO
  714.         tLen := usedMem - insPos;
  715.         IF tLen > 0 THEN 
  716.           ALLOCATE (tmpBuf, LONG(usedMem-insPos));
  717.           IF tmpBuf = NIL THEN RETURN FALSE END;
  718.           (* Jetzt ist ein tempor„rer Buffer da. *)
  719.           CopyBlock (ADR(buffer^[insPos]), tmpBuf, usedMem-insPos);
  720.           usedMem := insPos;
  721.         ELSE
  722.           tmpBuf := NIL;
  723.         END;
  724.         cBuf := currentBuff;
  725.         cNext := currentBuff^.next;
  726.         Block.Clear (ADR(buffer^[insPos]), currentBuff^.bufSize - insPos);
  727.  
  728.       END;
  729.       startByte := currentBuff^.bufSize - insPos-100;
  730.       IF startByte < 0 THEN startByte := currentBuff^.bufSize - insPos END;
  731.  
  732.       v.bool := appendToBuffer (buff, len, insPos, startByte, currentBuff^.bufSize - insPos);
  733.       (* Jetzt ist der Text aufgesplittet in mehrere Buffer. 
  734.        * Nun h„ngen wir noch den tempor„ren Buffer wieder dran, 
  735.        * Vorgehensweise ist die gleiche wie gerade, nur die Startposition ist 
  736.        * leicht ver„ndert, n„mlich jetzt das letzte Byte im aktuellen Buffer
  737.        * (usedMem).
  738.        *)
  739.       IF freeBuffer THEN DEALLOCATE (buff, 0); buff := NIL; END;
  740.  
  741.       (* Hier diese Position muž ich mir noch merken, um das Blockende festzustellen 
  742.        *)
  743.       bBuf := currentBuff;
  744.       bUsed := currentBuff^.usedMem;
  745.       
  746.       IF tLen > 0 THEN
  747.         startByte := currentBuff^.bufSize - currentBuff^.usedMem - 1000;
  748.         IF startByte < 0 THEN startByte := currentBuff^.bufSize - currentBuff^.usedMem-100 END;
  749.         IF startByte < 0 THEN startByte := currentBuff^.bufSize - currentBuff^.usedMem END;
  750.      
  751.         v.bool := appendToBuffer (tmpBuf, tLen, currentBuff^.usedMem, startByte, 
  752.                                   currentBuff^.bufSize - currentBuff^.usedMem);
  753.       END;
  754.       
  755.       (* So, jetzt setzen wir den currentBuff wieder auf den ersten, in
  756.        * den eingefgt wurde, und bauen die Zeilenstruktur neu auf!
  757.        *)
  758.       
  759.       currentBuff := cBuf;
  760.       first := TRUE;
  761.       WHILE currentBuff # cNext DO
  762.         WITH currentBuff^ DO
  763.           lineCount := countLines (currentBuff);
  764.           (* Wir haben also jetzt lineCount Zeilen in dem Buffer.
  765.            * Jetzt nachsehen, ob wir das Zeilenarray neu allozieren mssen 
  766.            *)
  767.           IF (lineCount >= maxLine) OR (lines = NIL) 
  768.           THEN
  769.             maxLine := BinOps.HigherInt (200, SHORT(BinOps.LowerLInt (32000L, (LONG(lineCount) * 3))) DIV 2);
  770.             IF lines # NIL THEN DEALLOCATE (lines, 0); END;
  771.             ALLOCATE (lines, LONG(maxLine) * TSIZE (INTEGER));
  772.             IF lines = NIL 
  773.             THEN 
  774.               (* Shit! Kein Speicher mehr! *)
  775.               (* Also wieder zurckkopieren und zurck *)
  776.               CopyBlock (tmpBuf, ADR(cBuf^.buffer^[insPos]), tLen);
  777.               cBuf^.usedMem := insPos + tLen;
  778.               (* Jetzt noch neu angeh„ngte Bl”cke l”schen *)
  779.               (* YYYY Hier mssen alle neuen Bl”cke freigegeben werden und
  780.                * noch was zurck kopiert werden. 
  781.                *)
  782.                
  783.               RETURN FALSE
  784.             END;
  785.           END;
  786.           IF first THEN
  787.             (* neue toLine berechnen *)
  788.             oldTo := toLine;
  789.             toLine := fromLine + LONG(lineCount) - 1;
  790.             startCount := toLine;
  791.             addLines := toLine - oldTo;
  792.           ELSE
  793.             fromLine := startCount + 1;
  794.             toLine := startCount + LONG(lineCount);
  795.             INC (addLines, lineCount);
  796.             INC (startCount, lineCount);
  797.           END;
  798.           fillLineArray (currentBuff);
  799.           first := FALSE;
  800.         END (* WITH *);
  801.         currentBuff := currentBuff^.next;
  802.       END; (* WHILE *)
  803.       
  804.       IF tmpBuf # NIL THEN DEALLOCATE (tmpBuf, 0); END;
  805.       
  806.       (* So, jetzt alle weiteren Zeilennummern anpassen *)
  807.       tBuf := cNext;
  808.       WHILE tBuf # NIL DO
  809.         INC (tBuf^.fromLine, addLines);
  810.         INC (tBuf^.toLine, addLines);
  811.         tBuf := tBuf^.next;
  812.       END;
  813.       INC (totalLineNr, addLines);
  814.       
  815.       (* Jetzt noch Position vom Blockende feststellen *) 
  816.       currentBuff := bBuf;
  817.   
  818.       IF block 
  819.       THEN 
  820.         GetPos (ed, bUsed, blocks[0].blockEnd.line, blocks[0].blockEnd.row); 
  821.       END;
  822.  
  823.       (* Und jetzt noch wieder komprimieren *)
  824.       v.bool := CompactBuffer (ed);
  825.     END;
  826.     (* Und jetzt noch aktuellen Buffer restaurieren *)
  827.     (* Das kann evtl. b”se in die Hose gehen, falls der Buffer wegkomprimiert wurde *)
  828. (*    currentBuff := cBuf;       *)
  829.     (*$? Debug:
  830.     TestStructure (ed);
  831.     *)
  832.   END (* WITH ed^ *);
  833.   RETURN TRUE;
  834. END InsertBuffer;
  835.  
  836. (*
  837. PROCEDURE CopyToBuff(VAR ed : EDITPTR; tStartLine, tEndLine : LONGINT; VAR addBuf : EditTypes.aBufferPtr) : BOOLEAN;
  838. (* Kopieren von einem EditBuffer in einen anderen.
  839.  * Es wird aus dem Editor in addBuf der Bereich von 
  840.  * tStartLine bis tEndLine kopiert.
  841.  *)
  842. VAR tBuf,
  843.     nBuf, 
  844.     listBuf : EditTypes.aBufferPtr;
  845.     i       : INTEGER;
  846.     
  847.  PROCEDURE freeTmpBuff();
  848.  BEGIN
  849.    (* Speicher freigeben *)
  850.    tBuf := addBuf;
  851.    WHILE tBuf # NIL DO
  852.      DEALLOCATE (tBuf^.buffer, 0);
  853.      IF tBuf^.lines # NIL THEN DEALLOCATE (tBuf^.lines, 0); END;
  854.      nBuf := tBuf^.next;
  855.      DISPOSE (tBuf);
  856.      tBuf := nBuf;
  857.    END;
  858.  END freeTmpBuff;
  859.  
  860. BEGIN
  861.   (* Startzeile suchen *)
  862.   IF tStartLine > 0 
  863.   THEN
  864.     IF ~findLineNum (ed, tStartLine-1) THEN RETURN FALSE END;
  865.   ELSE
  866.     ed^.currentBuff := ed^.firstBuff
  867.   END;
  868.   WITH ed^ DO 
  869.     (* Erstmal aus erstem Buffer kopieren *)
  870.     IF ~copyBuffer (ed, tStartLine-1, addBuf, v.int, TRUE)
  871.     THEN
  872.       RETURN FALSE
  873.     END;
  874.     addBuf^.next := NIL;
  875.     (* Jetzt ggf. weitere Buffer anh„ngen *)
  876.     IF tEndLine > addBuf^.toLine
  877.     THEN
  878.       (* weiter kopieren *)
  879.       listBuf := addBuf;
  880.       tBuf := currentBuff^.next;
  881.       REPEAT
  882.         IF tBuf # NIL
  883.         THEN
  884.           (* Einen kompletten Buffer kopieren und anh„ngen an addBuf *)
  885.           nBuf := createBuffer (0);
  886.           IF nBuf = NIL 
  887.           THEN
  888.             freeTmpBuff();
  889.             RETURN FALSE
  890.           END;
  891.           (* Speicher fr Zeilenarray anlegen *)
  892.           ALLOCATE (nBuf^.lines, LONG(tBuf^.maxLine) * TSIZE (INTEGER));
  893.           IF nBuf^.lines = NIL
  894.           THEN
  895.             freeTmpBuff();
  896.             RETURN FALSE;
  897.           END;
  898.           (* Jetzt kompletten Buffer kopieren *)
  899.           CopyBlock (tBuf^.buffer, nBuf^.buffer, currentBuff^.bufSize);
  900.           CopyBlock (tBuf^.lines, nBuf^.lines, LONG(tBuf^.maxLine)*TSIZE (INTEGER));
  901.           (* Struktur kopieren *)
  902.           nBuf^.usedMem  := tBuf^.usedMem;
  903.           nBuf^.maxLine  := tBuf^.maxLine;
  904.           nBuf^.fromLine := tBuf^.fromLine;
  905.           nBuf^.toLine   := tBuf^.toLine;
  906.           (* Jetzt an addBuff-Kette anh„ngen *)
  907.           listBuf^.next := nBuf;
  908.           nBuf^.prev :=listBuf; 
  909.           nBuf^.next := NIL;
  910.           listBuf := nBuf;
  911.           (* Jetzt n„chsten Block untersuchen *)
  912.           tBuf := tBuf^.next;
  913.         END (* IF *);
  914.       UNTIL (tBuf = NIL) OR (tBuf^.fromLine > tEndLine);
  915.       (* Jetzt noch letzte Endzeilennummer anpassen *)
  916.       listBuf^.toLine := tEndLine;
  917.     ELSE
  918.       WITH addBuf^ DO
  919.         toLine := tEndLine;
  920.         usedMem := 0;
  921.         FOR i := 0 TO SHORT(toLine-fromLine) DO 
  922.           INC (usedMem, lines^[i]);
  923.         END;
  924.       END;
  925.     END (* IF *);
  926.     (*$? Debug:
  927.     TestStructure (ed);
  928.     *)
  929.   END (* WITH *);
  930.   RETURN TRUE;
  931. END CopyToBuff;
  932. *)
  933.  
  934. PROCEDURE CopyToBuff(VAR ed : EDITPTR; tStartLine, tEndLine : LONGINT; 
  935.                      VAR addBuf : ADDRESS; VAR len : LONGCARD) : BOOLEAN;
  936. (* Kopieren von einem EditBuffer in einen Speicherbereich.
  937.  * Es wird aus dem Editor in addBuf der Bereich von 
  938.  * tStartLine bis tEndLine kopiert.
  939.  * Neue Fassung, die alles in einen Block kopiert und nicht in n kleine Bl”cke.
  940.  *)
  941. VAR tBuf    : EditTypes.aBufferPtr;
  942.     i       : INTEGER;
  943.     tBytes,
  944.     cBytes,
  945.     bytes   : LONGINT;
  946.     offset  : INTEGER;
  947.     fromAddr,
  948.     toAddr  : ADDRESS;
  949.     
  950. BEGIN
  951.   (* Startzeile suchen *)
  952.   IF tStartLine > 0 
  953.   THEN
  954.     IF ~findLineNum (ed, tStartLine-1) THEN RETURN FALSE END;
  955.   ELSE
  956.     ed^.currentBuff := ed^.firstBuff
  957.   END;
  958.   WITH ed^ DO 
  959.     IF tEndLine > totalLineNr - 1 THEN tEndLine := totalLineNr - 1 END;
  960.     (* Bytes zum Allozieren z„hlen *)
  961.     bytes := currentBuff^.usedMem;
  962.     offset := 0;
  963.     FOR i := 0 TO SHORT(tStartLine - currentBuff^.fromLine - 1) DO
  964.       DEC (bytes, currentBuff^.lines^[i]);
  965.       INC (offset, currentBuff^.lines^[i]);
  966.     END;
  967.     tBuf := currentBuff;
  968.     WHILE (tBuf # NIL) & (tEndLine > tBuf^.toLine) DO
  969.       tBuf := tBuf^.next;
  970.       IF tBuf # NIL
  971.       THEN
  972.         INC (bytes, tBuf^.usedMem);
  973.       END;
  974.     END;
  975.     FOR i := SHORT(tEndLine - tBuf^.fromLine + 1) TO SHORT(tBuf^.toLine - tBuf^.fromLine) DO
  976.       DEC (bytes, tBuf^.lines^[i]);
  977.     END;
  978.     IF bytes < 0 THEN HALT END;
  979.     INC (bytes, 10);        (* ein bižchen Sicherheit *)
  980.     ALLOCATE (addBuf, bytes);
  981.     IF addBuf = NIL THEN RETURN FALSE END;
  982.     
  983.     (* Jetzt den ganzen Kram in den Buffer kopieren *)
  984.     tBuf := currentBuff;
  985.     tBytes := bytes-10;
  986.     toAddr := addBuf;
  987.     fromAddr := ADR(tBuf^.buffer^[offset]);
  988.     IF tBytes < LONG(tBuf^.usedMem - offset)
  989.     THEN
  990.       CopyBlock (fromAddr, toAddr, tBytes);
  991.     ELSE
  992.       CopyBlock (fromAddr, toAddr, tBuf^.usedMem - offset);
  993.       DEC (tBytes, tBuf^.usedMem - offset);
  994.       INC (toAddr, tBuf^.usedMem - offset);
  995.       REPEAT
  996.         tBuf := tBuf^.next;
  997.         IF tBuf # NIL
  998.         THEN
  999.           cBytes := BinOps.LowerLInt (tBytes, tBuf^.usedMem);
  1000.           CopyBlock (tBuf^.buffer, toAddr, cBytes);
  1001.           INC (toAddr, cBytes);
  1002.           DEC (tBytes, cBytes);
  1003.         END;
  1004.       UNTIL (tBuf = NIL) OR (tBytes <= 0);
  1005.     END;
  1006.     len := bytes-10;
  1007.   END (* WITH *);
  1008.   RETURN TRUE;
  1009. END CopyToBuff;
  1010.  
  1011. (*
  1012. PROCEDURE CopyFromBuff(VAR ed : EDITPTR; tStartLine : LONGINT; addBuf : EditTypes.aBufferPtr; prev : BOOLEAN) : BOOLEAN;
  1013. (* Kopieren von einem EditBuffer in einen anderen.
  1014.  * Es wird der Sourcebuffer hinter oder vor die Zeile 
  1015.  * tStartLine angeh„ngt.
  1016.  * Vorgehensweise:
  1017.  *  - Zielbuffer hinter tStartLine splitten
  1018.  *  - Zeilen aus Source dahinter h„ngen (buffer einh„ngen)
  1019.  *  - Zeilennummern anpassen
  1020.  *  - compactBuffer laufen lassen, um Speicherbedarf einzuschr„nken
  1021.  *)
  1022.  VAR    tBuf    : EditTypes.aBufferPtr;
  1023.         lines   : LONGINT;
  1024.         i       : INTEGER;
  1025.         lineStart : LONGINT;
  1026.         
  1027. BEGIN
  1028.   IF prev THEN 
  1029.     DEC (tStartLine);
  1030.   END;
  1031.   IF tStartLine >= 0
  1032.   THEN
  1033.     (* Zeile suchen *)
  1034.     IF ~findLineNum (ed, tStartLine) THEN RETURN FALSE END;
  1035.     (* Buffer gezielt splitten *)
  1036.     IF ~splitBuffer (ed, tStartLine) THEN RETURN FALSE END;
  1037.   ELSE
  1038.     ed^.currentBuff := ed^.firstBuff;
  1039.   END;
  1040.   WITH ed^ DO
  1041.     (* Zeilennummern in angeh„ngten Buffern korrigieren *)
  1042.     tBuf := addBuf;
  1043.     lineStart := tStartLine + 1;
  1044.     lines := 0;
  1045.     WHILE tBuf # NIL DO
  1046.       INC (lines, tBuf^.toLine-tBuf^.fromLine+1);
  1047.       tBuf^.toLine := lineStart + tBuf^.toLine-tBuf^.fromLine;
  1048.       tBuf^.fromLine := lineStart;
  1049.       lineStart := tBuf^.toLine + 1;
  1050.       tBuf := tBuf^.next;
  1051.     END;
  1052.     (* Zeilennummern in Editorbuffern „ndern *)
  1053.     IF tStartLine = -1 THEN
  1054.       tBuf := currentBuff
  1055.     ELSE
  1056.       tBuf := currentBuff^.next;
  1057.     END;
  1058.     WHILE tBuf # NIL DO
  1059.       INC (tBuf^.toLine, lines);
  1060.       INC (tBuf^.fromLine, lines);
  1061.       tBuf := tBuf^.next;
  1062.     END;
  1063.     (* Zeilennummer fr Editor „ndern *)
  1064.     INC (totalLineNr, lines);
  1065.     (* anderen Buffer anh„ngen *)
  1066.     IF tStartLine = -1 THEN
  1067.       tBuf := currentBuff;
  1068.       firstBuff := addBuf;
  1069.       currentBuff := addBuf;
  1070.       addBuf^.prev := NIL;
  1071.     ELSE
  1072.       tBuf := currentBuff^.next;
  1073.       currentBuff^.next := addBuf;
  1074.       addBuf^.prev := currentBuff;
  1075.     END;
  1076.     WHILE addBuf^.next # NIL DO addBuf := addBuf^.next END;
  1077.     addBuf^.next := tBuf;
  1078.     tBuf^.prev := addBuf;
  1079.   END(*WITH*);
  1080.   (*$? Debug:
  1081.   TestStructure (ed);
  1082.   *)
  1083.   (* Jetzt Speicher kompaktieren *)
  1084.   v.bool := CompactBuffer (ed);
  1085.   RETURN TRUE
  1086. END CopyFromBuff;
  1087. *)
  1088.  
  1089. PROCEDURE GetOffset (VAR ed : EDITPTR) : INTEGER;
  1090. (* Setzt Buffer auf CurrentLine und berechnet Offset in 
  1091.  * currentBuffer fr currLineNr und currRow
  1092.  *)
  1093.   VAR offSet,
  1094.       i : INTEGER;
  1095. BEGIN
  1096.   WITH ed^ DO
  1097.     IF ~findLineNum (ed, currLineNr) THEN RETURN -1 END;
  1098.     (* Aktueller Buffer enth„lt lineNum *)
  1099.     WITH currentBuff^ DO
  1100.       offSet := 0;
  1101.       FOR i := 0 TO SHORT (currLineNr - fromLine) - 1 DO
  1102.         INC (offSet, lines^[i]);
  1103.       END;
  1104.     END;
  1105.     INC (offSet, currRow);
  1106.     RETURN offSet;
  1107.   END;
  1108. END GetOffset;
  1109.  
  1110. PROCEDURE GetPos (VAR ed : EDITPTR; offset : INTEGER; VAR line : LONGINT; VAR row : INTEGER);
  1111. (* Berechnet aus Offset in currentBuff die aktuelle
  1112.  * Zeile und Spalte
  1113.  *)
  1114.   VAR offset2,
  1115.       i         : INTEGER;
  1116. BEGIN
  1117.   WITH ed^ DO
  1118.     (* Aktueller Buffer enth„lt lineNum *)
  1119.     WITH currentBuff^ DO
  1120.       i := 0;
  1121.       offset2 := 0;
  1122.       WHILE (i <= SHORT(toLine - fromLine)) & (offset2 + lines^[i] <= offset) DO 
  1123.         INC (offset2, lines^[i]);
  1124.         INC (i);
  1125.       END;
  1126.       line := fromLine + LONG(i);
  1127.       row := offset - offset2;
  1128.     END;
  1129.   END;
  1130. END GetPos;
  1131.  
  1132. PROCEDURE GetLineLength (VAR ed : EDITPTR; lineNum : LONGINT; VAR len : INTEGER) : BOOLEAN;
  1133. (* Liefert die L„nge der Zeile lineNum
  1134.  * FALSE: Zeile nicht vorhanden.
  1135.  *)
  1136. BEGIN
  1137.   WITH ed^ DO
  1138.     IF (lineNum >= totalLineNr) OR (lineNum < 0) 
  1139.     THEN 
  1140.       len := 0; 
  1141.       eReason := notFound; 
  1142.       RETURN FALSE 
  1143.     END;
  1144.     (* Erst mal Buffer suchen und CurrentBuff entsprechend setzen *)
  1145.     IF ~findLineNum (ed, lineNum) THEN RETURN FALSE END;
  1146.     len := currentBuff^.lines^[SHORT(lineNum-currentBuff^.fromLine)];
  1147.     IF len = 0 THEN 
  1148.       (* Sollte nicht passieren, also Struktur korrigieren *)
  1149.       FixBuffer (ed);
  1150.       RETURN GetLineLength (ed, lineNum, len);
  1151.     END;
  1152.     IF lineNum = currLineNr THEN len := editLen END;
  1153.     RETURN TRUE;
  1154.   END;
  1155. END GetLineLength;
  1156.  
  1157. PROCEDURE GetLineAdr (VAR ed : EDITPTR; lineNum : LONGINT; VAR text : ADDRESS; VAR len : INTEGER) : BOOLEAN;
  1158. (* Liefert die Adresse der Zeile und die L„nge.
  1159.  * Nur fr Lesezugriff!
  1160.  * FALSE: Zeile nicht vorhanden
  1161.  *)
  1162.   VAR i   : INTEGER;
  1163.       offSet : INTEGER;
  1164. BEGIN
  1165.   WITH ed^ DO
  1166.     IF (lineNum >= totalLineNr) OR (lineNum < 0) 
  1167.     THEN 
  1168.       len := 0; 
  1169.       eReason := notFound; 
  1170.       RETURN FALSE 
  1171.     END;
  1172.     IF (lineNum = currLineNr) & editChanged
  1173.     THEN
  1174.       text := editLine.text;
  1175.       len := editLen;
  1176.       RETURN TRUE
  1177.     END;
  1178.     (* Erst mal Buffer suchen und CurrentBuff entsprechend setzen *)
  1179.     IF ~findLineNum (ed, lineNum) THEN RETURN FALSE END;
  1180.     (* Aktueller Buffer enth„lt lineNum *)
  1181.     offSet := 0;
  1182.     WITH currentBuff^ DO
  1183.       FOR i := 0 TO SHORT (lineNum - fromLine) - 1 DO
  1184.         INC (offSet, lines^[i]);
  1185.       END;
  1186.       len := lines^[SHORT(lineNum-fromLine)];
  1187.       text := ADR (buffer^[offSet]);
  1188.     END;
  1189.     RETURN TRUE;
  1190.   END;
  1191. END GetLineAdr;
  1192.  
  1193. PROCEDURE GetLine (VAR ed : EDITPTR; lineNum : LONGINT; VAR str : ARRAY OF CHAR; VAR len : INTEGER) : BOOLEAN;
  1194.   VAR text : ADDRESS;
  1195.       i    : INTEGER;
  1196.       found: BOOLEAN;
  1197. BEGIN
  1198.   WITH ed^ DO
  1199.     IF (lineNum = currLineNr) & editChanged THEN 
  1200.       CopyBlock (editLine.text, ADR (str), editLen);
  1201.       len := editLen;
  1202.       str[len] := 0C;
  1203.       RETURN TRUE
  1204.     END;
  1205.     IF ~GetLineAdr (ed, lineNum, text, len)
  1206.     THEN 
  1207.       str[0] := "";
  1208.       len := 0;
  1209.       RETURN FALSE
  1210.     END;
  1211.     eReason := lineToLong;
  1212.     IF len > INTEGER(HIGH (str)) THEN 
  1213.       CopyBlock (text, ADR(str), HIGH(str)-1);
  1214.       RETURN FALSE 
  1215.     END;
  1216.     CopyBlock (text, ADR(str), len);
  1217.     found := FALSE;
  1218.     FOR i := len-2 TO len-1 DO 
  1219.       IF (i >= 0) & ((str[i] = LF) OR (str[i] = CR)) THEN found := TRUE END;
  1220.     END;
  1221.     IF ~found THEN
  1222.       str[len] := CR;
  1223.       str[len+1] := LF;
  1224.       INC (len,2);
  1225.     END;
  1226.     str[len] := 0C;
  1227.     RETURN TRUE;
  1228.   END;
  1229. END GetLine;
  1230.  
  1231. PROCEDURE PutLine (VAR ed : EDITPTR; lineNum : LONGINT; VAR str : ARRAY OF CHAR; len : INTEGER) : BOOLEAN;
  1232.   VAR oldLen : INTEGER;
  1233.       offSet : INTEGER;
  1234.       i      : INTEGER;
  1235. BEGIN
  1236.   WITH ed^ DO
  1237.     IF (lineNum > totalLineNr) OR (lineNum < 0) 
  1238.     THEN 
  1239.       len := 0; 
  1240.       eReason := notFound;
  1241.       RETURN FALSE 
  1242.     END;
  1243.     (* Erst mal Buffer suchen und CurrentBuff entsprechend setzen *)
  1244.     IF ~findLineNum (ed, lineNum) THEN RETURN FALSE END;
  1245.     (* Aktueller Buffer enth„lt lineNum *)
  1246.     WITH currentBuff^ DO
  1247.       offSet := 0;
  1248.       FOR i := 0 TO SHORT (lineNum - fromLine) - 1 DO
  1249.         INC (offSet, lines^[i]);
  1250.       END;
  1251.       oldLen := lines^[SHORT(lineNum-fromLine)];
  1252.       IF len <= oldLen
  1253.       THEN 
  1254.         (* Easy, Zeile nur kopieren, und evtl. was nachschieben von hinten *)
  1255.         CopyBlock (ADR(str),ADR(buffer^[offSet]), len);
  1256.         IF len < oldLen
  1257.         THEN
  1258.           CopyBlock (ADR(buffer^[offSet+oldLen]),ADR(buffer^[offSet+len]), usedMem - offSet - oldLen); 
  1259.           (* Benutzen Speicher updaten *)
  1260.           DEC (usedMem, oldLen-len);
  1261.         END;
  1262.         lines^[SHORT(lineNum-fromLine)] := len;
  1263.         RETURN TRUE;
  1264.       ELSE
  1265.         (* Jetzt wird es echt schwierig: Ich muž erst nachsehen, ob 
  1266.          * noch genug Platz im aktuellen Buffer ist. Wenn das nicht 
  1267.          * der Fall ist, dann muž ich einen neuen Buffer allozieren
  1268.          * und ca. 50% des Blocks auslagern. Wenn das auch nicht mehr 
  1269.          * geht (kein Speicher mehr fr Buffer), dann muž ich eine 
  1270.          * Garbage Collection machen (Alle Bl”cke zusammenschieben)
  1271.          * und dann das nochmal versuchen.
  1272.          *)
  1273.         eReason := notEnoughMem;
  1274.         IF usedMem - oldLen  < currentBuff^.bufSize - len
  1275.         THEN 
  1276.           (* Ok, pažt noch rein *)
  1277.           (* Bytes nach hinten schieben *)
  1278.           CopyBlock (ADR (buffer^[offSet+oldLen]),ADR(buffer^[offSet+len]), usedMem - offSet - oldLen); 
  1279.           (* Zeile einfgen *)
  1280.           CopyBlock (ADR(str), ADR(buffer^[offSet]), len);
  1281.           (* Benutzen Speicher im Block hochz„hlen *)
  1282.           INC (usedMem, len - oldLen);
  1283.           lines^[SHORT(lineNum-fromLine)] := len;
  1284.           RETURN TRUE;
  1285.         ELSE
  1286.           (* Nicht genug Platz, also neuen Buffer anh„ngen *)
  1287.           IF ~splitBuffer (ed,-1)
  1288.           THEN 
  1289.             RETURN FALSE 
  1290.           END;
  1291.           (* Und jetzt mssen wir nur noch die eigentliche Zeile einfgen.
  1292.            * Da ich faul bin, mache ich das einfach durch eine Rekursion 
  1293.            *)
  1294.           RETURN PutLine (ed, lineNum, str, len);
  1295.         END;
  1296.       END;
  1297.     END (* WITH currentBuff^ DO *);
  1298.   END (* WITH ed^ DO *)
  1299. END PutLine;
  1300.  
  1301. PROCEDURE InsertCr (VAR ed : EDITPTR; lineNum : LONGINT; row : INTEGER) : BOOLEAN;
  1302. (* Trennt die Zeile lineNum an der Stelle row auf.
  1303.  * FALSE: Kein Speicherplatz mehr frei.
  1304.  *)
  1305.   VAR lineIdx : INTEGER;
  1306.       newArray: EditTypes.lineArrayPtr;
  1307.       buff    : EditTypes.aBufferPtr;
  1308.       doFixBuf: BOOLEAN;
  1309. BEGIN
  1310.   WITH ed^ DO
  1311.     IF (lineNum > totalLineNr) OR (lineNum < 0) 
  1312.     THEN 
  1313.       eReason := notFound; 
  1314.       RETURN FALSE 
  1315.     END;
  1316.     WITH currentBuff^ DO
  1317.       (* Wir suchen einfach nach der Zeile und fgen 
  1318.        * noch einen Eintrag im LineArray an.
  1319.        *)
  1320.       eReason := notEnoughMem;
  1321.       lineIdx := SHORT(lineNum - fromLine);
  1322.       IF SHORT (toLine - fromLine) + 1 >= maxLine 
  1323.       THEN
  1324.         (* LineArray neu allozieren *)
  1325.         ALLOCATE (newArray, LONG(maxLine + 20) * TSIZE (INTEGER));
  1326.         IF newArray = NIL THEN RETURN FALSE END;
  1327.         CopyBlock (lines, newArray, maxLine * TSIZE (INTEGER));
  1328.         DEALLOCATE (lines, 0);
  1329.         lines := newArray;
  1330.         INC (maxLine, 20);
  1331.       END;
  1332.       (* Platz im LineArray ist jetzt garantiert da! *)
  1333.       (* Zeilenindex einfgen *)
  1334.       doFixBuf := FALSE;
  1335.       (* Prfen, ob eine Zeile 0 Byte lang werden wrde *)
  1336.       IF (lines^[lineIdx] = row) OR (row = 0) THEN 
  1337.       (*$? Debug:
  1338.         TestStructure (ed);
  1339.       *)
  1340.         FixLine (ed, lineNum);
  1341.         RETURN InsertCr (ed, lineNum, row);
  1342.       END;
  1343.       CopyBlock (ADR(lines^[lineIdx]), ADR(lines^[lineIdx+1]), (SHORT(toLine - fromLine) - lineIdx + 1) * TSIZE (INTEGER)); 
  1344.       lines^[lineIdx+1] := lines^[lineIdx] - row; 
  1345.       IF lines^[lineIdx+1] = 0 THEN doFixBuf := TRUE; END;
  1346.       lines^[lineIdx] := row; 
  1347.       IF lines^[lineIdx] = 0 THEN doFixBuf := TRUE; END;
  1348.       INC (toLine);
  1349.       INC (totalLineNr);
  1350.       buff := currentBuff^.next;
  1351.       WHILE (buff # NIL) DO
  1352.         INC (buff^.fromLine);
  1353.         INC (buff^.toLine);
  1354.         buff := buff^.next;
  1355.       END;
  1356.       IF doFixBuf
  1357.       THEN
  1358.         FixBuffer (ed);
  1359.       END;
  1360.     END;
  1361.   END;
  1362.   RETURN TRUE
  1363. END InsertCr; 
  1364.  
  1365. PROCEDURE InsertLine (VAR ed : EDITPTR; lineNum : LONGINT; VAR str : ARRAY OF CHAR; pre : BOOLEAN; len : INTEGER) : BOOLEAN;
  1366. (* Fgt die Zeile lineNum im Buffer ein.
  1367.  * Wenn pre = TRUE ist, dann wird die Zeile vor die alte Zeile lineNum gesetzt,
  1368.  * ansonsten hinter die Zeile lineNum.
  1369.  * Ergebnis: FALSE: Nicht genug Speicher mehr frei
  1370.  *) 
  1371.  VAR buff : EditTypes.aBufferPtr;
  1372.      newArray : EditTypes.lineArrayPtr;
  1373.      offset,
  1374.      lineIdx,
  1375.      i        : INTEGER;
  1376. BEGIN
  1377.   WITH ed^ DO
  1378.     IF (lineNum > totalLineNr) OR (lineNum < 0) 
  1379.     THEN 
  1380.       eReason := notFound; 
  1381.       RETURN FALSE 
  1382.     END;
  1383.     (* Wir fgen immer hinter der Zeile ein. Bei pre wird
  1384.      * einfach lineNum dekrementiert 
  1385.      *)
  1386.     eReason := notEnoughMem;
  1387.     IF pre THEN DEC (lineNum) END;
  1388.     IF lineNum = -1
  1389.     THEN
  1390.       currentBuff := firstBuff;
  1391.       offset := 0;
  1392.       lineIdx := 0;
  1393.     ELSE
  1394.       IF ~findLineNum (ed, lineNum) THEN RETURN FALSE END;
  1395.       WITH currentBuff^ DO
  1396.         offset := 0;
  1397.         FOR i := 0 TO SHORT(lineNum - fromLine) DO
  1398.           INC (offset, lines^[i]);
  1399.         END;
  1400.         lineIdx := SHORT(lineNum - fromLine)+1;
  1401.       END;
  1402.     END;
  1403.     (* Jetzt sind offset und Buffer bestimmt *)
  1404.     WITH currentBuff^ DO
  1405.       IF usedMem < currentBuff^.bufSize - len
  1406.       THEN
  1407.         (* Ok, pažt noch rein *)
  1408.         IF SHORT (toLine - fromLine) + 4 >= maxLine - 1
  1409.         THEN
  1410.           (* LineArray neu allozieren *)
  1411.           ALLOCATE (newArray, LONG(maxLine + 20) * TSIZE (INTEGER));
  1412.           IF newArray = NIL THEN RETURN FALSE END;
  1413.           CopyBlock (lines, newArray, maxLine * TSIZE (INTEGER));
  1414.           DEALLOCATE (lines, 0);
  1415.           lines := newArray;
  1416.           INC (maxLine, 20);
  1417.         END;
  1418.         (* Platz im LineArray ist jetzt garantiert da! *)
  1419.         (* Zeilenindex einfgen *)
  1420.         (*
  1421.         CopyBlock (ADR(lines^[lineIdx]), ADR(lines^[lineIdx+1]), (SHORT(toLine - fromLine + 1) - lineIdx + 1) * TSIZE (INTEGER));
  1422.         *)
  1423.         FOR i := SHORT(toLine - fromLine + 1) TO lineIdx BY -1 DO
  1424.           lines^[i+1] :=  lines^[i];
  1425.         END;
  1426.         lines^[lineIdx] := len;
  1427.         CopyBlock (ADR (buffer^[offset]), ADR(buffer^[offset+len]), usedMem - offset); 
  1428.         CopyBlock (ADR (str), ADR (buffer^[offset]), len);
  1429.         INC (usedMem, len);
  1430.         (* Jetzt Zeilenverweise updaten in allen folgenden Buffern *)
  1431.         INC (toLine);
  1432.         INC (totalLineNr);
  1433.         buff := currentBuff^.next;
  1434.         WHILE (buff # NIL) DO
  1435.           INC (buff^.fromLine);
  1436.           INC (buff^.toLine);
  1437.           buff := buff^.next;
  1438.         END;
  1439.       ELSE
  1440.         (* Nicht genug Platz im aktuellen Buffer! Also das alte Spiel:
  1441.          * Splitten und dann nochmal versuchen 
  1442.          *)
  1443.         IF ~splitBuffer (ed, -1)
  1444.         THEN RETURN FALSE END;
  1445.         RETURN InsertLine (ed, lineNum, str, FALSE, len);
  1446.       END;
  1447.     END;
  1448.   END;
  1449.   RETURN TRUE
  1450. END InsertLine;
  1451.  
  1452. PROCEDURE DeleteSomeLines (VAR ed : EDITPTR; from, to : LONGINT) : BOOLEAN;
  1453. (* L”scht einen Bereich von Zeilen ber mehrere Bl”cke hinweg 
  1454.  * Dabei wird mittels deleteLineBlock in den „užeren Bl”cken 
  1455.  * gel”scht und die inneren Bl”cke entfernt.
  1456.  *)
  1457.   VAR zBuf, tBuf : EditTypes.aBufferPtr;
  1458.       lineCount : INTEGER;
  1459. BEGIN
  1460.   (* Buffer suchen zu Zeile *)
  1461.   IF ~findLineNum (ed, from) THEN RETURN FALSE END;
  1462.   WITH ed^ DO
  1463.     to := BinOps.LowerLInt (to, totalLineNr - 1);
  1464.     IF currentBuff^.toLine >= to
  1465.     THEN
  1466.       IF ~deleteLineBlock (ed, from, to)
  1467.       THEN
  1468.         RETURN FALSE
  1469.       END;
  1470.     ELSE
  1471.       IF from = currentBuff^.fromLine
  1472.       THEN
  1473.         (* currentBuff komplett l”schen *)
  1474.         tBuf := currentBuff;
  1475.         DEALLOCATE (tBuf^.buffer, 0);
  1476.         DEALLOCATE (tBuf^.lines, 0);
  1477.         IF tBuf^.prev # NIL
  1478.         THEN
  1479.           tBuf^.prev^.next := tBuf^.next;
  1480.         END;
  1481.         IF tBuf^.next # NIL
  1482.         THEN
  1483.           tBuf^.next^.prev := tBuf^.prev;
  1484.         END;
  1485.         IF firstBuff = currentBuff
  1486.         THEN
  1487.           firstBuff := currentBuff^.next;
  1488.         END;
  1489.         currentBuff := currentBuff^.next;
  1490.         DISPOSE (tBuf);
  1491.       ELSE
  1492.         IF ~deleteLineBlock (ed, from, currentBuff^.toLine)
  1493.         THEN RETURN FALSE END;
  1494.         currentBuff^.toLine := from-1;
  1495.         currentBuff := currentBuff^.next;
  1496.       END;
  1497.       WHILE (currentBuff # NIL) & (to > currentBuff^.toLine) DO
  1498.         (* Buffer komplett freigeben *)
  1499.         tBuf := currentBuff;
  1500.         IF tBuf^.prev # NIL
  1501.         THEN
  1502.           tBuf^.prev^.next := tBuf^.next;
  1503.         END;
  1504.         IF tBuf^.next # NIL
  1505.         THEN
  1506.           tBuf^.next^.prev := tBuf^.prev;
  1507.         END;
  1508.         IF firstBuff = currentBuff
  1509.         THEN
  1510.           firstBuff := currentBuff^.next;
  1511.         END;
  1512.         currentBuff := currentBuff^.next;
  1513.         DEALLOCATE (tBuf^.buffer, 0);
  1514.         DEALLOCATE (tBuf^.lines, 0);
  1515.         DISPOSE (tBuf);
  1516.       END;
  1517.       (* Jetzt noch restliche Zeilen l”schen *)
  1518.       IF ~deleteLineBlock (ed, currentBuff^.fromLine, to)
  1519.       THEN 
  1520.         RETURN FALSE
  1521.       END;
  1522.       currentBuff^.fromLine := from;
  1523.     END;
  1524.     WITH currentBuff^ DO
  1525.       lineCount := SHORT(to - from) + 1;
  1526.       (* Zeilenverweise anpassen *)
  1527.       DEC (ed^.totalLineNr, lineCount);
  1528.       DEC (toLine, lineCount);
  1529.       tBuf := next;
  1530.       WHILE tBuf # NIL DO 
  1531.         DEC (tBuf^.fromLine, lineCount);
  1532.         DEC (tBuf^.toLine, lineCount);
  1533.         tBuf := tBuf^.next;  
  1534.       END;
  1535.     END;
  1536.     (*$? Debug:
  1537.     TestStructure (ed);
  1538.     *)
  1539.   END;
  1540.   RETURN TRUE;
  1541. END DeleteSomeLines;
  1542.  
  1543. PROCEDURE DeleteLine (VAR ed : EDITPTR; lineNum : LONGINT) : BOOLEAN;
  1544. (* L”scht die Zeile lineNum im Buffer
  1545.  * FALSE: Zeile nicht vorhanden 
  1546.  *)
  1547.  VAR i,
  1548.      lineIdx,
  1549.      len,
  1550.      offset     : INTEGER;
  1551.      lineCount  : INTEGER;
  1552.      buff       : EditTypes.aBufferPtr;
  1553. BEGIN
  1554.   WITH ed^ DO
  1555.     IF (lineNum > totalLineNr) OR (lineNum < 0) 
  1556.     THEN 
  1557.       eReason := notFound; 
  1558.       RETURN FALSE 
  1559.     END;
  1560.     IF ~findLineNum (ed, lineNum) THEN RETURN FALSE END;
  1561.     WITH currentBuff^ DO
  1562.       (* Zeile l”schen *)
  1563.       IF ~deleteLineBlock (ed, lineNum, lineNum) 
  1564.       THEN 
  1565.         RETURN FALSE
  1566.       END;
  1567.     (*
  1568.       offset := 0;
  1569.       FOR i := 0 TO SHORT(lineNum - fromLine) - 1 DO
  1570.         INC (offset, lines^[i]);
  1571.       END;
  1572.       lineIdx := SHORT(lineNum - fromLine);
  1573.       len := lines^[lineIdx];
  1574.       (* LineArray anpassen *)
  1575.       CopyBlock (ADR(lines^[lineIdx+1]), ADR(lines^[lineIdx]), SHORT (toLine - lineNum + 1) * TSIZE (INTEGER)); 
  1576.       (* Im Speicher verschieben *)
  1577.       CopyBlock (ADR (buffer^[offset+len]), ADR (buffer^[offset]), usedMem - offset - len); 
  1578.       (* usedMem anpassen *)
  1579.       DEC (usedMem, len);
  1580.       (* Zeilenverweise anpassen *)
  1581.       DEC (totalLineNr);
  1582.       DEC (toLine);
  1583.       buff := next;
  1584.       WHILE buff # NIL DO 
  1585.         DEC (buff^.fromLine);
  1586.         DEC (buff^.toLine);
  1587.         buff := buff^.next;
  1588.       END;
  1589.     *)
  1590.       lineCount := 1;
  1591.       (* Zeilenverweise anpassen *)
  1592.       DEC (ed^.totalLineNr, lineCount);
  1593.       IF totalLineNr = 0 
  1594.       THEN
  1595.         totalLineNr := 1;
  1596.         lineCount := SHORT(toLine);
  1597.       END;
  1598.       DEC (toLine, lineCount);
  1599.       buff := next;
  1600.       WHILE buff # NIL DO 
  1601.         DEC (buff^.fromLine, lineCount);
  1602.         DEC (buff^.toLine, lineCount);
  1603.         buff := buff^.next;
  1604.       END;
  1605.       IF usedMem < currentBuff^.bufSize DIV 4
  1606.       THEN 
  1607.         (* weniger als 25 % belegt,
  1608.          * Buffer mit folgendem oder vorherigem zusammenlegen
  1609.          *)
  1610.         IF next # NIL
  1611.         THEN
  1612.           v.bool := compactTwo (currentBuff, currentBuff^.next, v.bool);
  1613.         ELSIF prev # NIL
  1614.         THEN
  1615.           v.bool := compactTwo (currentBuff^.prev, currentBuff, v.bool);
  1616.         END;
  1617.       END;
  1618.       IF currLineNr = editLineNr
  1619.       THEN 
  1620.         editChanged := FALSE;
  1621.       END;
  1622.       IF currLineNr >= totalLineNr THEN
  1623.         currLineNr := totalLineNr - 1
  1624.       END;
  1625.     END;
  1626.   END;
  1627.   RETURN TRUE;
  1628. END DeleteLine;
  1629.  
  1630. PROCEDURE CompactBuffer (VAR ed : EDITPTR) : BOOLEAN;
  1631. (* Kompaktiert den Bufferspeicher. FALSE: Nicht mehr m”glich, da
  1632.  * gar kein Speicher mehr frei war.
  1633.  *)
  1634.  VAR buffOne : EditTypes.aBufferPtr;
  1635.      freedSecond,
  1636.      success : BOOLEAN;
  1637. BEGIN
  1638.   WITH ed^ DO
  1639.     buffOne := firstBuff;
  1640.     success := TRUE;
  1641.     WHILE (buffOne # NIL) & (buffOne^.next # NIL) DO
  1642.       v.bool := compactTwo (buffOne, buffOne^.next, freedSecond);
  1643.       success := success AND v.bool;
  1644.       IF ~freedSecond
  1645.       THEN
  1646.         buffOne := buffOne^.next;
  1647.       END;
  1648.     END;
  1649.     currentBuff := firstBuff;
  1650.   END;
  1651.   RETURN success;
  1652. END CompactBuffer;
  1653.  
  1654. PROCEDURE GetCurrLine (VAR ed : EDITPTR; VAR str : ARRAY OF CHAR; VAR len : INTEGER);
  1655. (* Liefert die aktuelle Zeile, in der der Cursor steht.
  1656.  *)
  1657. BEGIN
  1658.   v.bool := GetLine (ed, ed^.currLineNr, str, len);
  1659. END GetCurrLine;
  1660.  
  1661. PROCEDURE PutCurrLine (VAR ed : EDITPTR): BOOLEAN;
  1662. (* Schiebt die aktuelle Zeile, in der der Cursor steht, wieder in den Buffer
  1663.  *)
  1664.   VAR res : BOOLEAN;
  1665. BEGIN
  1666.   WITH ed^ DO
  1667.     IF editChanged
  1668.     THEN
  1669.       (*$? Debug:
  1670.       IF editLen # INTEGER((*SYSTEM.*)LENGTH (editLine.text^))
  1671.       THEN HALT END;
  1672.       *)
  1673.       IF editLen=0
  1674.       THEN
  1675.         editLine.text^ := CR+LF+0C;
  1676.         editLen := 2;
  1677.       END;
  1678.       res := PutLine (ed, currLineNr, editLine.text^, editLen);
  1679.       IF ~res & ~CompactBuffer (ed)
  1680.       THEN 
  1681.         RETURN FALSE;
  1682.       ELSIF ~res
  1683.       THEN
  1684.         IF ~PutLine (ed, currLineNr, editLine.text^, editLen)
  1685.         THEN 
  1686.           RETURN FALSE
  1687.         END;
  1688.       END;
  1689.       editChanged := FALSE;
  1690.     END
  1691.   END;
  1692.   RETURN TRUE;
  1693. END PutCurrLine;
  1694.  
  1695. PROCEDURE GetBuffer (VAR ed : EDITPTR; defSize : INTEGER) : BOOLEAN;
  1696. (* Erzeugt einen neuen Buffer hinter currentBuff
  1697.  * Es wird nur der Textbuffer und der Descriptor alloziert,
  1698.  * das LineArray noch nicht.
  1699.  *)
  1700.   VAR newBuff : EditTypes.aBufferPtr;
  1701. BEGIN
  1702.   WITH ed^ DO
  1703.     newBuff := createBuffer (defSize);
  1704.     IF newBuff = NIL THEN RETURN FALSE END;
  1705.     (* Jetzt kommt das Einh„ngen in die Liste *)
  1706.     IF firstBuff = NIL
  1707.     THEN
  1708.       newBuff^.prev := NIL;
  1709.       newBuff^.next := NIL;
  1710.       firstBuff := newBuff;
  1711.       currentBuff := firstBuff;
  1712.     ELSE
  1713.       IF currentBuff = NIL
  1714.       THEN
  1715.         currentBuff := firstBuff;
  1716.       END;
  1717.       newBuff^.prev := currentBuff;
  1718.       newBuff^.next := currentBuff^.next;
  1719.       IF newBuff^.next # NIL
  1720.       THEN
  1721.         newBuff^.next^.prev := newBuff;
  1722.       END;
  1723.       currentBuff^.next := newBuff;
  1724.       currentBuff := newBuff;
  1725.     END;
  1726.   END;
  1727.   RETURN TRUE;
  1728. END GetBuffer;
  1729.  
  1730. PROCEDURE FreeBuffer (VAR ed : EDITPTR);
  1731.   VAR buff : EditTypes.aBufferPtr;
  1732. BEGIN
  1733.   WITH ed^ DO
  1734.     IF currentBuff = NIL THEN RETURN END;
  1735.     IF currentBuff^.prev # NIL
  1736.     THEN
  1737.       currentBuff^.prev^.next := currentBuff^.next;
  1738.     END;
  1739.     IF currentBuff^.next # NIL
  1740.     THEN
  1741.       currentBuff^.next^.prev := currentBuff^.prev;
  1742.     END;
  1743.     IF firstBuff = currentBuff
  1744.     THEN
  1745.       firstBuff := currentBuff^.next;
  1746.     END;
  1747.     buff := currentBuff;
  1748.     currentBuff := currentBuff^.next;
  1749.     IF buff^.buffer # NIL THEN DEALLOCATE (buff^.buffer, 0); END;
  1750.     IF buff^.lines # NIL THEN DEALLOCATE (buff^.lines, 0); END;
  1751.     DISPOSE (buff);
  1752.   END;
  1753. END FreeBuffer;
  1754.  
  1755. PROCEDURE CountBytes (VAR ed: EDITPTR; lineFrom : LONGINT; rowFrom: INTEGER;
  1756.                       lineTo: LONGINT; rowTo: INTEGER; VAR bytes: LONGCARD);
  1757. (* Z„hlt die Bytes, die von dem Text zwischen den beiden Textmarken belegt werden
  1758.  *)
  1759.   VAR buff : EditTypes.aBufferPtr;
  1760.       offset: INTEGER;
  1761.       i     : INTEGER;
  1762. BEGIN
  1763.   WITH ed^ DO
  1764.     IF ~findLineNum (ed, lineTo) 
  1765.     OR ~findLineNum (ed, lineFrom) 
  1766.     THEN 
  1767.       bytes := 0;
  1768.       RETURN
  1769.     END;
  1770.     WITH currentBuff^ DO 
  1771.       offset := 0;
  1772.       FOR i := 0 TO SHORT(lineFrom - fromLine) - 1 DO
  1773.         INC (offset, lines^[i]);
  1774.       END;
  1775.       INC (offset, rowFrom);
  1776.       bytes := usedMem - offset;
  1777.     END;
  1778.     (* Jetzt Endebuffer suchen *)
  1779.     WHILE (currentBuff # NIL) & (lineTo > currentBuff^.toLine) DO
  1780.       INC (bytes, currentBuff^.usedMem);
  1781.       currentBuff := currentBuff^.next;
  1782.     END;
  1783.     IF currentBuff # NIL
  1784.     THEN
  1785.       offset := 0;
  1786.       WITH currentBuff^ DO
  1787.         FOR i := 0 TO SHORT(lineTo - fromLine) - 1 DO
  1788.           INC (offset, lines^[i]);
  1789.         END;
  1790.       END;
  1791.       INC (offset, rowTo);
  1792.       INC (bytes, offset);
  1793.     ELSE
  1794.       bytes := 0;
  1795.       RETURN
  1796.     END;
  1797.   END;
  1798. END CountBytes;
  1799.  
  1800. BEGIN
  1801.   CopyBlock := blockCopy;
  1802. END EditBase.
  1803.